/*
 * File      : drv_i2c.c
 * This file is part of RT-Thread RTOS
 * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Change Logs:
 * Date           Author       Notes
 * 2017-06-05     tanek        first implementation.
 * 2018-09-15     BalanceTWK   Change to hardware i2c.
 */

#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

#define I2C_TIMEOUT 100

//#define DRV_I2C_DEBUG
#define DBG_ENABLE
#define DBG_SECTION_NAME  "drv.i2c"
#define DBG_COLOR
#ifdef DRV_I2C_DEBUG
#define DBG_LEVEL DBG_LOG
#else
#define DBG_LEVEL DBG_INFO
#endif
#include <rtdbg.h>

/*user can change this*/
#ifdef RT_USING_HW_I2C

struct stm32_i2c
{
    struct rt_i2c_bus_device parent;
    char *device_name;
	I2C_HandleTypeDef *handle;
};

static struct stm32_i2c i2c1 =
{
    .device_name = "i2c1",
};

static rt_size_t i2c_mst_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num);

static const struct rt_i2c_bus_device_ops i2c_ops =
{
    i2c_mst_xfer,
    NULL,
    NULL,
};


static rt_size_t i2c_mst_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num)
{
    struct stm32_i2c *stm32_i2c;

    RT_ASSERT(bus != RT_NULL);
    stm32_i2c = (struct stm32l4_i2c_bus *) bus;

    if (num == 1)
    {
        if (msgs[0].flags & RT_I2C_RD)
        {
            if (HAL_I2C_Master_Receive(stm32_i2c->handle, msgs[0].addr << 1, msgs[0].buf, msgs[0].len, I2C_TIMEOUT) != HAL_OK)
            {
                return 0;
            }
        }
        else
        {
            if (HAL_I2C_Master_Transmit(stm32_i2c->handle, msgs[0].addr << 1, msgs[0].buf, msgs[0].len, I2C_TIMEOUT) != HAL_OK)
            {
                return 0;
            }
        }
    }
    else if (num == 2)
    {
        if (msgs[1].flags & RT_I2C_RD)
        {
            if (HAL_I2C_Mem_Read(stm32_i2c->handle, msgs[0].addr << 1, *msgs[0].buf, msgs[0].len, msgs[1].buf, msgs[1].len, I2C_TIMEOUT) != HAL_OK)
            {
                return 0;
            }
        }
        else
        {
            if (HAL_I2C_Mem_Write(stm32_i2c->handle, msgs[0].addr << 1, *msgs[0].buf, msgs[0].len, msgs[1].buf, msgs[1].len, I2C_TIMEOUT) != HAL_OK)
            {
                return 0;
            }
        }
    }

    return num;
}

void MX_I2C1_Init(void);

int rt_hw_i2c_init(void)
{
	MX_I2C1_Init();

	i2c1.parent.ops = &i2c_ops;
	i2c1.handle = I2C1;

    rt_i2c_bus_device_register(&i2c1.parent, i2c1.device_name);

    return 0;
}

INIT_DEVICE_EXPORT(rt_hw_i2c_init);

#endif /* end of BSP_USING_I2C */
